//
// Created by changlei on 2022/4/25.
//

import Foundation
import UIKit
import WebKit


protocol ChromePlaceholder {
    func add(_ viewable: Viewable, to contentView: UIView)

    func remove(_ viewable: Viewable, from contentView: UIView)
}

class ViewableChromeController: BaseController {
    private var viewable: Viewable!
    private var placeholder: ChromePlaceholder!
    private var isLoadingObservation: NSKeyValueObservation?

    var isReadOnly: Bool = false {
        didSet {
            statusBar.isHidden = isReadOnly
            bottomBar.isHidden = isReadOnly
        }
    }

    lazy private var statusBar: UIView = {
        let uiView = UIView()
        uiView.isHidden = isReadOnly
        return uiView
    }()
    lazy private var webView: WKWebView = {
        let wkWebView = WKWebView()
        wkWebView.allowsBackForwardNavigationGestures = true
        return wkWebView
    }()
    lazy private var activityIndicator: UIActivityIndicatorView = {
        let indicatorView = UIActivityIndicatorView()
        indicatorView.style = .large
        indicatorView.hidesWhenStopped = true
        return indicatorView
    }()
    lazy private var bottomBar: UIPlainTabBar = {
        let tabBar = UIPlainTabBar()
        tabBar.isHidden = isReadOnly
        return tabBar
    }()

    private var themeColorObservation: NSKeyValueObservation?
    private var backgroundColorObservation: NSKeyValueObservation?

    convenience init(_ viewable: Viewable, placeholder: ChromePlaceholder = DefaultPlaceholder(), isReadOnly: Bool = false) {
        self.init()
        self.viewable = viewable
        self.placeholder = placeholder
        self.isReadOnly = isReadOnly
        let options: NSKeyValueObservingOptions = [.new, .initial]
        themeColorObservation = webView.observe(\.themeColor, options: options) { (webView, change) in
            self.statusBar.backgroundColor = webView.themeColor ?? .white
        }
        backgroundColorObservation = webView.observe(\.underPageBackgroundColor, options: options) { (webView, change) in
            self.view.backgroundColor = webView.underPageBackgroundColor ?? .clear
        }
        isLoadingObservation = webView.observe(\.isLoading, options: options) { (webView, change) in
            if webView.isLoading {
                self.showIndicator()
            } else {
                self.hideIndicator()
            }
        }
    }

    deinit {
        themeColorObservation?.invalidate()
        backgroundColorObservation?.invalidate()
        isLoadingObservation?.invalidate()
        webView.stopLoading()
    }

    func showIndicator() {
        placeholder.add(viewable, to: view)
    }

    func hideIndicator() {
        placeholder.remove(viewable, from: view)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationBar?.isHidden = true
        showIndicator()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationBar?.isHidden = false
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(statusBar)
        statusBar.snp.makeConstraints { make in
            make.top.equalToSuperview()
            make.leading.equalTo(view.safeAreaLayoutGuide.snp.leading)
            make.trailing.equalTo(view.safeAreaLayoutGuide.snp.trailing)
            make.bottom.equalTo(view.safeAreaLayoutGuide.snp.top)
        }

        view.addSubview(webView)
        webView.load(viewable.url)
        webView.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
            make.leading.trailing.bottom.equalToSuperview()
        }

        view.addSubview(bottomBar)
    }
}

extension WKWebView {
    @discardableResult
    func load(_ url: String) -> WKNavigation? {
        if let url = URL(string: url) {
            load(URLRequest(url: url))
        }
        return nil
    }
}

class DefaultPlaceholder: ChromePlaceholder {
    func add(_ viewable: Viewable, to contentView: UIView) {
    }

    func remove(_ viewable: Viewable, from contentView: UIView) {
    }
}